package com.vben.common.mybatisplus.base;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.PageUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.Data;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 通用分页响应实体，用于封装后端分页查询结果并返回给前端
 * <p>
 * 提供 MyBatis Plus 分页结果快速转换能力，支持分页导航彩虹条和扩展字段，
 * 适用于前后端分页数据交互场景
 * </p>
 *
 * @param <T> 分页数据列表中的数据类型
 */
@Data
public class CommonPage<T> {

    /**
     * 分页彩虹条默认展示的页码数量（当前页前后各延伸两个页码）
     */
    public static final int RAINBOW_NUM = 5;

    /**
     * 总记录数
     * <p>示例：100</p>
     */
    private int total;

    /**
     * 总分页数
     * <p>示例：10</p>
     */
    private int pages;

    /**
     * 每页记录数
     * <p>示例：10</p>
     */
    private int size;

    /**
     * 当前页码（从1开始）
     * <p>示例：1</p>
     */
    private int current;

    /**
     * 当前页数据列表
     */
    private List<T> records;

    /**
     * 分页彩虹条页码数组
     * <p>用于前端生成页码导航，示例：[3,4,5,6,7]</p>
     */
    private int[] rainbow;

    /**
     * 扩展字段容器
     * <p>可用于存放分页之外的附加业务数据，格式：{key1:value1, key2:value2}</p>
     */
    private Dict ext;

    /**
     * 将 MyBatis Plus 分页对象转换为通用分页对象
     *
     * @param page MyBatis Plus 分页对象（输入）
     * @param <T>  记录数据类型
     * @return 无扩展字段的通用分页结果
     */
    public static <T> CommonPage<T> convert(IPage<T> page) {
        return convert(page, null, Dict.create());
    }

    /**
     * 转换为指定数据类型的通用分页对象
     *
     * @param page  源分页对象（输入）
     * @param clazz 目标数据类型Class对象（输入）
     * @param <T>   源数据类型
     * @param <R>   目标数据类型
     * @return 带类型转换的分页结果
     */
    public static <T, R> CommonPage<R> convert(IPage<T> page, Class<R> clazz) {
        return convert(page, clazz, Dict.create());
    }

    /**
     * 转换为带扩展字段的通用分页对象
     *
     * @param page 源分页对象（输入）
     * @param ext  扩展字段字典（输入）
     * @param <T>  记录数据类型
     * @return 包含扩展字段的分页结果
     */
    public static <T> CommonPage<T> convert(IPage<T> page, Dict ext) {
        return convert(page, null, ext);
    }

    /**
     * 核心转换方法（带类型转换和扩展字段）
     *
     * @param page  源分页对象（输入）
     * @param clazz 目标数据类型Class对象（可选）
     * @param ext   扩展字段字典（可选）
     * @param <T>   源数据类型
     * @param <R>   目标数据类型
     * @return 完整的分页结果对象
     */
    @SuppressWarnings("unchecked")
    public static <T, R> CommonPage<R> convert(IPage<T> page, Class<R> clazz, Dict ext) {
        CommonPage<R> result = new CommonPage<>();

        // 设置分页元数据
        result.setTotal((int) page.getTotal());
        result.setPages((int) page.getPages());
        result.setSize((int) page.getSize());
        result.setCurrent((int) page.getCurrent());

        // 执行数据转换
        if (clazz != null) {
            result.setRecords(page.getRecords().stream()
                    .map(record -> BeanUtil.toBean(record, clazz))
                    .collect(Collectors.toList()));
        } else {
            result.setRecords((List<R>) page.getRecords());
        }

        // 生成彩虹条
        result.setRainbow(PageUtil.rainbow(
                result.getCurrent(),
                result.getPages(),
                RAINBOW_NUM
        ));

        // 处理扩展字段
        result.setExt(ext != null ? ext : Dict.create());

        return result;
    }
}